package com.xujie.sportsmeeting.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xujie.sportsmeeting.common.exception.BusinessException;
import com.xujie.sportsmeeting.common.result.ResultCode;
import com.xujie.sportsmeeting.entity.CompetitionEvent;
import com.xujie.sportsmeeting.entity.EventRegistration;
import com.xujie.sportsmeeting.mapper.EventRegistrationMapper;
import com.xujie.sportsmeeting.service.CompetitionEventService;
import com.xujie.sportsmeeting.service.EventRegistrationService;
import com.xujie.sportsmeeting.event.RegistrationAuditPassedEvent;
import org.springframework.context.ApplicationEventPublisher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 项目报名服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EventRegistrationServiceImpl extends ServiceImpl<EventRegistrationMapper, EventRegistration> implements EventRegistrationService {

    private final CompetitionEventService competitionEventService;
    private final ApplicationEventPublisher eventPublisher;

    @Override
    @Transactional
    public boolean registerEvent(Long eventId, Long athleteId, String remarks) {
        // 检查项目是否存在
        CompetitionEvent event = competitionEventService.getById(eventId);
        if (event == null) {
            throw new BusinessException(ResultCode.EVENT_NOT_FOUND);
        }

        // 检查是否可以报名
        if (!competitionEventService.canRegister(eventId)) {
            throw new BusinessException(ResultCode.EVENT_REGISTRATION_CLOSED);
        }

        // 检查是否已经报名
        if (hasRegistered(eventId, athleteId)) {
            throw new BusinessException(ResultCode.REGISTRATION_EXISTS);
        }

        // 创建报名记录
        EventRegistration registration = new EventRegistration();
        registration.setEventId(eventId);
        registration.setAthleteId(athleteId);
        registration.setRegistrationNumber(generateRegistrationNumber(eventId));
        registration.setRegistrationTime(LocalDateTime.now());
        registration.setAuditStatus(0); // 待审核
        registration.setRemarks(remarks);
        registration.setStatus(1);

        return save(registration);
    }

    @Override
    @Transactional
    public boolean auditRegistration(Long registrationId, Integer auditStatus, String auditRemark, Long auditUserId) {
        EventRegistration registration = getById(registrationId);
        if (registration == null) {
            throw new BusinessException(ResultCode.REGISTRATION_NOT_FOUND);
        }

        // 只能审核待审核状态的报名
        if (registration.getAuditStatus() != 0) {
            throw new BusinessException(ResultCode.REGISTRATION_AUDIT_ERROR, "该报名已审核，不能重复审核");
        }

        registration.setAuditStatus(auditStatus);
        registration.setAuditTime(LocalDateTime.now());
        registration.setAuditUserId(auditUserId);
        registration.setAuditRemark(auditRemark);

        boolean updateResult = updateById(registration);
        
        // 如果审核通过，发布审核通过事件
        if (updateResult && auditStatus == 1) {
            try {
                RegistrationAuditPassedEvent event = new RegistrationAuditPassedEvent(
                    this,
                    registrationId,
                    registration.getEventId(),
                    registration.getAthleteId(),
                    auditUserId
                );
                eventPublisher.publishEvent(event);
                log.info("发布报名审核通过事件: registrationId={}", registrationId);
            } catch (Exception e) {
                log.error("发布审核通过事件异常: registrationId={}", registrationId, e);
                // 这里不抛出异常，避免影响审核流程
            }
        }
        
        return updateResult;
    }

    @Override
    public boolean hasRegistered(Long eventId, Long athleteId) {
        LambdaQueryWrapper<EventRegistration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EventRegistration::getEventId, eventId)
               .eq(EventRegistration::getAthleteId, athleteId)
               .eq(EventRegistration::getStatus, 1);
        return count(wrapper) > 0;
    }

    @Override
    public List<EventRegistration> getEventRegistrations(Long eventId) {
        LambdaQueryWrapper<EventRegistration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EventRegistration::getEventId, eventId)
               .eq(EventRegistration::getStatus, 1)
               .orderByDesc(EventRegistration::getCreateTime);
        return list(wrapper);
    }

    @Override
    public List<EventRegistration> getAthleteRegistrations(Long athleteId) {
        LambdaQueryWrapper<EventRegistration> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EventRegistration::getAthleteId, athleteId)
               .eq(EventRegistration::getStatus, 1)
               .orderByDesc(EventRegistration::getCreateTime);
        return list(wrapper);
    }

    @Override
    @Transactional
    public boolean cancelRegistration(Long registrationId, Long athleteId) {
        EventRegistration registration = getById(registrationId);
        if (registration == null) {
            throw new BusinessException(ResultCode.REGISTRATION_NOT_FOUND);
        }

        // 验证操作权限
        if (!registration.getAthleteId().equals(athleteId)) {
            throw new BusinessException(ResultCode.FORBIDDEN, "只能取消自己的报名");
        }

        // 只能取消待审核的报名
        if (registration.getAuditStatus() != 0) {
            throw new BusinessException(ResultCode.REGISTRATION_AUDIT_ERROR, "已审核的报名不能取消");
        }

        registration.setStatus(0); // 取消状态
        return updateById(registration);
    }

    @Override
    public String generateRegistrationNumber(Long eventId) {
        // 生成报名编号：REG + 项目ID + 时间戳后6位
        String timestamp = String.valueOf(System.currentTimeMillis());
        String suffix = timestamp.substring(timestamp.length() - 6);
        return "REG" + String.format("%03d", eventId) + suffix;
    }
}
